#include "global.h"

#define BROKEN_PIPE_ERROR	-1

void show_pipe(Pipe* p)
{
	int i = 0, pos = p->tail;
	printf("***************************************\n");
	printf("Data: %d characters currently in pipe\n", p->data);
	printf("Room: %d character slots open in pipe\n", p->room);
	printf("Pipe Contents: \"");
	for (i = 0; i < p->data; ++i)
	{
		if (pos == PIPE_SIZE)
			pos = 0;
		printf("%c", p->buf[pos++]);
	}
	printf("\"\n***************************************\n");
}

void do_pipe(int* pfd)
{
	int i = 0, rfd = -1, wfd = -1, urfd = -1, uwfd = -1;
	Pipe* pipePtr = 0;
	
	pfd[0] = -1;
	pfd[1] = -1;
	
	for (i = 0; i < NUM_PIPES; i += 2)
	{
		if (pipes[i].status == PIPE_FREE)
		{
			pipePtr = &pipes[i];
			pipePtr->head = pipePtr->tail = pipePtr->data = 0;
			pipePtr->room = PIPE_SIZE;
			pipePtr->status = PIPE_USED;
			pipePtr->numReader = 1;
			pipePtr->numWriter = 1;
			
			break;
		}
	}
	
	if (pipePtr == 0)
		return;
	
	for (i = 0; i < NUM_FILE_DESC; i += 2)
	{
		if ((fileEntries[i].refCount == 0) &&
			(fileEntries[i + 1].refCount == 0))
		{
			fileEntries[i].mode = READ_PIPE;
			fileEntries[i].refCount = 1;
			fileEntries[i].pipePtr = pipePtr;
			rfd = i;
			
			fileEntries[i + 1].mode = WRITE_PIPE;
			fileEntries[i + 1].refCount = 1;
			fileEntries[i + 1].pipePtr = pipePtr;
			wfd = i + 1;
			break;
		}
	}
	
	if ((rfd == -1) || (wfd == -1))
		return;
	
	for (i = 0; i < NUM_FILE_DESC; ++i)
	{
		if ((running->fileDescriptors[i] == 0) &&
			(running->fileDescriptors[i + 1] == 0))
		{
			running->fileDescriptors[i] = &fileEntries[rfd];
			urfd = i;
			
			running->fileDescriptors[i + 1] = &fileEntries[wfd];
			uwfd = i + 1;
			
			break;
		}
	}
	
	if ((urfd == -1) || (uwfd == -1))
		return;
	
	pfd[0] = urfd;
	pfd[1] = uwfd;
}

int read_pipe(int fd, char* buf, int nbytes)
{
	int bytesRead = 0;
	Pipe* rpipe = running->fileDescriptors[fd]->pipePtr;
	
	printf("Before read...\n");
	show_pipe(rpipe);
	
	while ((rpipe->data == 0) && (rpipe->numWriter > 0))
	{
		wakeup(WRITE_PIPE);
		sleep(READ_PIPE);
	}
	while ((bytesRead < nbytes) && (rpipe->data > 0))
	{
		if (rpipe->tail == PIPE_SIZE)
			rpipe->tail = 0;
		buf[bytesRead++] = rpipe->buf[rpipe->tail++];
		--rpipe->data;
		++rpipe->room;
	}
	wakeup(WRITE_PIPE);
	printf("After read...\n");
	show_pipe(rpipe);
	
	return bytesRead;
}

int write_pipe(int fd, char* buf, int nbytes)
{
	int bytesWritten = 0;
	Pipe* wpipe = running->fileDescriptors[fd]->pipePtr;
	
	if (wpipe->numReader > 0)
	{
		printf("Before write...\n");
		show_pipe(wpipe);
		while (bytesWritten < nbytes)
		{
			while (wpipe->room == 0)
			{
				printf("After write...\n");
				show_pipe(wpipe);
				wakeup(READ_PIPE);
				sleep(WRITE_PIPE);
				printf("Before write...\n");
				show_pipe(wpipe);
			}
			if (wpipe->head == PIPE_SIZE)
				wpipe->head = 0;
			wpipe->buf[wpipe->head++] = buf[bytesWritten++];
			--wpipe->room;
			++wpipe->data;
		}
		wakeup(READ_PIPE);
		printf("After write...\n");
		show_pipe(wpipe);
		return bytesWritten;
	}
	
	return BROKEN_PIPE_ERROR;
}
